home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc Source Code / Messaging / OSL / OSLBldSt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-22  |  28.7 KB  |  965 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        OSLBldSt.c (Orignal name: OSLBuildStructs.c)
  3.  
  4.     Contains:    
  5.  
  6.     Owned by:    Nick Pilch
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <2>     1/15/96    TJ        Cleaned Up
  13.          <4>     1/12/95    jpa        Don't use obsolete Toolbox names [1211211]
  14.          <3>    11/15/94    NP        1191221-added warning at call of PtrToHand.
  15.          <2>     8/19/94    NP        1181622: Ownership fix.
  16.          <7>      5/2/94    eeh        bug #1160654: various PPC native changes
  17.          <6>     11/2/93    NP        Moved back pascal keyword for MPW C.
  18.          <5>     11/2/93    NP        Move pascal keyword.
  19.          <4>    10/22/93    NP        Removed unnecessary assignment, and thus,
  20.                                     compiler warning.
  21.          <3>     7/28/93    NP        Mods for new token type, OSLToken.
  22.          <2>     7/21/93    NP        Fixed #includes.
  23.          <1>     7/21/93    NP        first checked in
  24.  
  25.     To Do:
  26.     In Progress:
  27. */
  28.  
  29. /*                                            
  30.     ©Apple Computer, Inc.  1992         
  31.           All Rights Reserved.                
  32.     Author: Eric House
  33.                                             */
  34.  
  35.  
  36. #include "OSLPriv.h"
  37. #include <SetJmp.h>
  38.  
  39. #pragma segment AEObjSuppt
  40.  
  41. static OSErr
  42. ClearNewHandle( Handle *theH, long size )
  43. {
  44.         *theH = NewHandleClear( size ) ;
  45.         return MemError() ;
  46. }
  47.  
  48.  
  49.  
  50. ///////////////////////////////////////////////////////////////////////////////
  51. // MakeWhoseDescriptor
  52. // packs the selection data for a 'whose' naming form. This type of naming
  53. // names the desired object by specifying an identifying test. This is
  54. // probably a pretty familiar form of utility by this point, but essentially
  55. // it makes up the record, fills in fields from the parameters, and packs them
  56. // into a descriptor.
  57. ///////////////////////////////////////////////////////////////////////////////
  58.  
  59. static OSErr
  60. MakeWhoseDescriptor(    AEDesc *indexOrRel, AEDesc *test, AEDesc* theDescriptor )
  61. {
  62.     AERecord whoseRecord ;
  63.     OSErr err = noErr ;
  64.     
  65.     err = AECreateList( NULL, 0, true, &whoseRecord ) ;        // create the record
  66.     if ( err != noErr ) goto L100 ;
  67.     
  68.     // the indexOrRel field, which says which object or objects that meet 
  69.     // the test are desired, this index can also be a relative record
  70.  
  71.     err = AEPutKeyDesc( &whoseRecord, keyAEIndex, indexOrRel ) ;
  72.     if ( err != noErr ) goto L100 ;
  73.  
  74.     // now we fill in the test we will use
  75.  
  76.     err = AEPutKeyDesc( &whoseRecord, keyAETest, test ) ;
  77.     if ( err != noErr ) goto L100 ;
  78.  
  79.     // dispose of input
  80.  
  81.     IgnoreOSErr( AEDisposeDesc( indexOrRel ) ) ;
  82.     IgnoreOSErr( AEDisposeDesc( test ) ) ;
  83.     
  84.     // coerce record to descriptor
  85.     err =  AECoerceDesc( &whoseRecord, typeWhoseDescriptor, theDescriptor ) ;
  86.     if ( err == noErr ) goto L200 ;
  87.  
  88. L100:
  89.     MakeNull( theDescriptor ) ;
  90. L200:
  91.     IgnoreOSErr( AEDisposeDesc( &whoseRecord ) ) ;
  92.     return err ;
  93. } // MakeWhoseDescriptor
  94.  
  95.  
  96.     /*———————————————————————— CreateCompare ————————————————————————*/
  97.  
  98. OSErr
  99. CreateCompare( AEDesc  input , Comparison *theComparison )
  100. /*create a comparison record from a descriptor of type typeCompDescriptor*/
  101. {
  102.     AERecord         tempRecord ;
  103.     DescType         ignoreReturnedType ;            /* <eeh> never checked */
  104.     long         actualSize ;
  105.     AEDesc         tempObject ;
  106.     OSErr          err ;
  107.  
  108.  
  109.     err = ClearNewHandle( (Handle *)theComparison, sizeof( CompareRecord ) ) ;
  110.     if ( err != noErr ) goto L100 ;
  111.     
  112.     /*            Using NewHandleClear saves the following calls:
  113.     WITH theComparison** DO
  114.     {
  115.     obj1 = NULL ;
  116.     obj2 = NULL ;
  117.     value = false ;
  118.     redo = false ;
  119.     } ; */
  120.     
  121.     HLock( (Handle)*theComparison ) ;
  122.     
  123.     err = AEDuplicateDesc( &input, &(**theComparison)->theCompInput ) ;
  124.     if ( err != noErr ) goto L200 ;
  125.     
  126.     err = AECoerceDesc( &input, typeAERecord, &tempRecord ) ;
  127.     if ( err != noErr ) goto L300 ;
  128.     
  129. //    WITH theComparison** DO
  130.     {
  131.         ComparePtr cp = **theComparison ;
  132.         
  133.         err = AEGetKeyPtr( &tempRecord, keyAECompOperator,
  134.                             typeEnumerated, &ignoreReturnedType,
  135.                             (Ptr)&cp->oper, sizeof(cp->oper), &actualSize ) ;
  136.         if ( err != noErr ) goto L350 ;
  137.         
  138.         err = AEGetKeyDesc( &tempRecord, keyAEObject1, typeWildCard, &tempObject ) ;
  139.         if ( err != noErr ) goto L350 ;
  140.         
  141.         err = CreateObject( &tempObject, NULL, true, &cp->obj1 ) ;        /* obj1 is NULL until set here */
  142.         if ( err != noErr ) goto L400 ;
  143.         
  144.         IgnoreOSErr( AEDisposeDesc( &tempObject ) )  ;
  145.         err = AEGetKeyDesc( &tempRecord, keyAEObject2, typeWildCard, &tempObject ) ;
  146.         if ( err != noErr ) goto L450 ;
  147.         
  148.         err = CreateObject( &tempObject, NULL, true, &cp->obj2 ) ;        /* obj2 is NULL until set here */
  149.         IgnoreOSErr( AEDisposeDesc( &tempObject ) ) ;
  150.         
  151.         /*okay, we've got all of the data, now we set the redo flag so that the first
  152.         time we evaluate the comparison, everything tries to evaluate at least once*/
  153.         cp->redo = true;
  154.     }
  155.     
  156.     IgnoreOSErr( AEDisposeDesc( &tempRecord ) )  ;
  157.     HUnlock( (Handle) *theComparison ) ;
  158.     
  159.     if ( err != noErr )
  160.     {
  161.     DisposeObj( (**theComparison)->obj2 ) ;
  162. L450:
  163.     DisposeObj( (**theComparison)->obj1 ) ;
  164. L400:
  165.     IgnoreOSErr( AEDisposeDesc( &tempObject ) ) ;
  166. L350:
  167.     IgnoreOSErr( AEDisposeDesc( &tempRecord ) ) ;
  168. L300:
  169.     if ( SetErrDesc( (**theComparison)->theCompInput ) )
  170.         (**theComparison)->theCompInput.dataHandle = NULL ;
  171. L200:
  172.     DisposeHandle( (Handle)*theComparison ) ;
  173.     theComparison = NULL ;                                        /* 4/11 caller's fail will attempt a second dispose */
  174.     }
  175. L100:
  176.     
  177.     return err ;
  178.     
  179. } /*CreateCompare*/
  180.  
  181.     
  182.     /*———————————————————————— CreateLogical ————————————————————————*/
  183.  
  184. /*create a logical record from a descriptor of type typeLogicalDescriptor*/
  185. OSErr
  186. CreateLogical( const AEDesc *input , Logical *theLogical )
  187.         
  188. {
  189.     AERecord         tempRecord ;
  190.     AEDesc         tempList ;
  191.     long         nTerms ;
  192.     AEKeyword         ignoredKeyword ;
  193.     AEDesc         dThisTerm ;
  194.     Term         thisTerm ;
  195.     Term         lastTerm ;
  196.     DescType         theReturnedType ;
  197.     long         actualSize ;
  198.     long         I ;
  199.  
  200.     OSErr err = noErr;
  201.  
  202.     tempRecord.dataHandle = NULL;
  203.     tempList.dataHandle = NULL;
  204.     lastTerm = NULL;
  205.     
  206.     FailErr( ClearNewHandle( (Handle *)theLogical, sizeof(LogicalRecord) ),
  207.         err, errExit ) ;
  208.  
  209. /*            Using NewHandleClear saves the following calls:
  210. WITH theLogical** DO
  211. {
  212. firstTerm = NULL ;
  213. value = false ;
  214. redo = false ;
  215. } ; */
  216.  
  217.     HLock( (Handle) *theLogical ) ;
  218.     
  219.     FailErr( AEDuplicateDesc( input, &(**theLogical)->theLogicalInput ),
  220.             err, errExit ) ;
  221.     FailErr( AECoerceDesc(input, typeAERecord, &tempRecord), err, errExit);
  222.  
  223.     //WITH theLogical** DO
  224.     {
  225.         LogicalPtr lp = **theLogical ;
  226.     
  227.         FailErr( AEGetKeyPtr( &tempRecord, keyAELogicalOperator, typeEnumerated,
  228.                 &theReturnedType, (Ptr)&lp->logicalOp, sizeof(lp->logicalOp),
  229.                 &actualSize), err, errExit) ;
  230.     
  231.         FailErr( AEGetKeyDesc( &tempRecord, keyAELogicalTerms, typeWildCard,
  232.                 &tempList ), err, errExit ) ;
  233.         
  234.         FailErr( AECountItems( &tempList, &nTerms), err, errExit ) ;
  235.         
  236.         for( I = 1; I <=nTerms; ++I )        /* build a linked list of comparisons */
  237.         {
  238.             FailErr( AEGetNthDesc( &tempList, I, typeWildCard, &ignoredKeyword,
  239.                     &dThisTerm), err, errExit ) ;
  240.             FailErr( CreateTerm( &dThisTerm, &thisTerm ), err, errExit ) ;
  241.             
  242.             if ( lastTerm == NULL )
  243.             {
  244.                 lp->firstTerm = thisTerm;
  245.                 lastTerm = thisTerm;
  246.             }
  247.             else
  248.                 {
  249.                     (*lastTerm)->next = thisTerm;
  250.                     lastTerm = thisTerm;
  251.                 }
  252.             
  253.         } /*for*/
  254.             
  255.         /*set the redo flag so that everything tries to evaluate at least once*/
  256.         lp->redo = true;
  257.     }
  258.  
  259.     HUnlock( (Handle)*theLogical ) ;
  260.     
  261.     IgnoreOSErr( AEDisposeDesc( &tempRecord) ) ;
  262.     IgnoreOSErr( AEDisposeDesc( &tempList ) ) ;
  263.  
  264. FAIL_ERR_PROC(err, errExit)
  265.     if ( theLogical != NULL )
  266.     {
  267.         if ( SetErrDesc( (**theLogical)->theLogicalInput ) )
  268.             (**theLogical)->theLogicalInput.dataHandle = NULL ;
  269.         DisposeTerm( (**theLogical)->firstTerm) ;
  270.     };
  271.     DisposeHandle( (Handle)*theLogical ) ;
  272.     *theLogical = NULL;
  273.  
  274.     IgnoreOSErr( AEDisposeDesc( &tempRecord ) ) ;
  275.     IgnoreOSErr( AEDisposeDesc( &tempList ) ) ;
  276.     IgnoreOSErr( AEDisposeDesc( &dThisTerm ) ) ;
  277. END_FAIL_ERR_PROC(err)
  278. } /*CreateLogical*/
  279.         
  280.  
  281.     /*———————————————————————— CreateObject ————————————————————————*/
  282.  
  283. extern pascal Boolean IsKnownAbso( DescType abso ) ;
  284.  
  285. /* RangeIsWhoseable: eeh 2/1/90
  286. Determine if ( a range can be converted to data that can be inserted into the structure for
  287. resolving whose descriptors; if ( it can, convert it to a special type desc and pass it
  288. back.
  289. */
  290. #define cleanupNow false
  291.  
  292. /* A bit different from the FailErr()s.  RangeIsWhoseable returns a Boolean 
  293.  * rather than an error, so I can use ExitIfNot to bail whenever, even to 
  294.  * clean up when there's been no error */
  295.  
  296.  
  297. static void
  298. ExitIfNot( Boolean b, jmp_buf *jbp )
  299. {
  300.     if ( !b )
  301.     {
  302.         longjmp( *jbp, 1 ) ;
  303.     }
  304. }
  305.  
  306. #define sizeZero  0
  307. static OSErr
  308. GetWhoseEndPoint( AEDesc dEndObj, long  *value , DescType *valCase,
  309.         AEDesc tempRIWRecord, DescType objClass, jmp_buf *jbp ) 
  310.  
  311. {
  312.     DescType                      theReturnedType ;
  313.     DescType                      scratch ;                    /* used as temporary storage for all sorts of tests */                
  314.     long                      actualSize ;
  315.     OSErr err = noErr ;
  316.     
  317.     IgnoreOSErr( AEDisposeDesc( &tempRIWRecord ) ) ;
  318.     FailErr( AECoerceDesc( &dEndObj, typeAERecord, &tempRIWRecord ),
  319.             err, errExit ) ;
  320.     FailErr( AEGetKeyPtr( &tempRIWRecord, keyAEContainer, typeWildCard,
  321.         &theReturnedType, NULL, sizeZero, &actualSize ), err, errExit ) ;
  322.     ExitIfNot( theReturnedType == typeCurrentContainer, jbp ) ;
  323.     FailErr( AEGetKeyPtr( &tempRIWRecord, keyAEDesiredClass, typeType,
  324.         &theReturnedType, (Ptr)&scratch, SizeOf(scratch), &actualSize),
  325.         err, errExit ) ;
  326.     ExitIfNot( scratch == objClass, jbp ) ;
  327.     FailErr( AEGetKeyPtr( &tempRIWRecord, keyAEKeyForm, typeEnumerated,
  328.         &theReturnedType, (Ptr)&scratch, sizeof(scratch), &actualSize),
  329.         err, errExit ) ;
  330.     ExitIfNot( scratch == formAbsolutePosition, jbp ) ;
  331.     FailErr( AEGetKeyPtr( &tempRIWRecord, keyAEKeyData, typeWildCard, valCase,
  332.         (Ptr)value, sizeof(*value), &actualSize), err, errExit ) ;
  333.     ExitIfNot( (actualSize == sizeof(value)) 
  334.                 && ((*valCase == typeAbsoluteOrdinal)
  335.                 || (*valCase == typeLongInteger)), jbp ) ;
  336.  
  337. FAIL_ERR_PROC(err, errExit)
  338. END_FAIL_ERR_PROC(err)
  339. }  /* GetWhoseEndPoint */
  340.  
  341.  
  342. static Boolean
  343. RangeIsWhoseable( DescType objClass, AEDesc rangeDesc,
  344.     IndexRecord *index, OSErr *externalErr ) 
  345. {
  346.     AEDesc dStartObj, dStopObj ;
  347.     AEDesc                  tempRIWRecord ;
  348.     OSErr                  err ;
  349.     Boolean retVal = false ;
  350.     jmp_buf jb ;
  351.     
  352.     dStartObj.dataHandle = NULL ;
  353.     dStopObj.dataHandle = NULL ;
  354.     tempRIWRecord.dataHandle = NULL ;
  355.  
  356.     *externalErr = noErr ;
  357.  
  358.     if (setjmp( jb) )        // we'll come back here if it is determined that
  359.     {                                    // the answer is false
  360. //        IgnoreOSErr( AEDisposeDesc( &tempRIWRecord ) ) ;
  361. //        IgnoreOSErr( AEDisposeDesc( &dStartObj ) ) ;
  362. //        IgnoreOSErr( AEDisposeDesc( &dStopObj ) ) ;
  363.         retVal = false ;
  364.         err = noErr ;
  365.         goto errExit ;                // not really an error, but...
  366.     }                    
  367.  
  368.     FailErr( AECoerceDesc( &rangeDesc, typeAERecord, &tempRIWRecord ),
  369.             err, errExit ) ;
  370.     
  371.     FailErr( AEGetKeyDesc( &tempRIWRecord, keyAERangeStart, typeWildCard,
  372.             &dStartObj ), err, errExit  ) ;
  373.     FailErr( AEGetKeyDesc( &tempRIWRecord, keyAERangeStop, typeWildCard,
  374.         &dStopObj ), err, errExit ) ;
  375.  
  376.     FailErr( GetWhoseEndPoint( dStartObj, &index->startValue, &index->startCase, 
  377.             tempRIWRecord, objClass, (jmp_buf *)&jb ), err, errExit ) ;
  378.     FailErr( GetWhoseEndPoint( dStopObj, &index->stopValue, &index->stopCase,
  379.             tempRIWRecord, objClass, (jmp_buf *)&jb ), err, errExit ) ;
  380.     
  381.     retVal = true ;            /* if we've gotten this far, it's true */
  382. //    ExitIfNot( cleanupNow ) ;
  383.  
  384.  
  385. errExit :
  386.     IgnoreOSErr( AEDisposeDesc( &dStartObj) ) ;
  387.     IgnoreOSErr( AEDisposeDesc( &dStopObj) ) ;
  388.     IgnoreOSErr( AEDisposeDesc( &tempRIWRecord) ) ;
  389.     *externalErr = err ;
  390.     return retVal ;
  391.  
  392. }  /* RangeIsWhoseable */
  393.  
  394.  
  395. /* CombineObjects:
  396.  * this could be done without parameters, but I find this style much easier
  397.  * to read and to maintain.
  398.  * Combines two objects into one.  On entry, objWithTest has selectionData
  399.  * that needs to be moved to objWithIndex, whose selectionData should
  400.  * already have been disposed of.
  401. */
  402. static void
  403. CombineObjects( Object *objWithTest, Object *objWithIndex )
  404. {
  405.     Object tempContainerH ;            /* used for swapping */
  406.  
  407. //WITH objWithTest** DO
  408.     {
  409.         ObjRecordPtr orp = **objWithTest ;
  410.     
  411.         IgnoreOSErr( AEDisposeDesc( &orp->theObjInput ) ) ;
  412.         (**objWithIndex)->u.objForm = formWhose ;
  413.         (**objWithIndex)->objContainer = orp->objContainer ;
  414.         (**objWithIndex)->objSelectionData = orp->objSelectionData ;
  415.         if ( orp->objContainer != NULL )
  416.             (*(orp->objContainer))->objContained = *objWithIndex ;
  417.         tempContainerH = orp->objContainer ;                                            
  418.         orp->objContainer = NULL ;                                /* so DisposeObj doesn't follow the chain */
  419.         orp->objSelectionData.dataHandle = NULL ;            /* " */
  420.         DisposeObj( *objWithTest ) ;
  421.     }
  422.  
  423.     *objWithTest = tempContainerH ;                                    /* so the current makeobj call returns right values */
  424. }  /* CombineObjects */
  425.  
  426.  
  427. /*create a term record from either a typeLogicalDescriptor or a typeCompDescriptor.
  428.  Do not dispose input: app may own it.*/
  429. OSErr
  430. CreateObject( const AEDesc  *input , Object  containedObj,
  431.         Boolean  expandWhoseData, Object *theObject )
  432.         
  433.     {
  434.     AEDesc          tempObject ;
  435.     AEDesc          tempRecord ;
  436.     DescType          theReturnedType ;
  437.     Size          actualSize;
  438.     Object          newObj ;
  439.     Boolean          canCombine ;
  440.     //Boolean          disposedSelf ;            /* if dispose self for optimization, don't unlock Handle! */
  441.     IndexRecord         index ; 
  442.     
  443.     
  444.     OSErr err = noErr;
  445.     
  446.     tempObject.dataHandle = NULL;
  447.     tempRecord.dataHandle = NULL;
  448.     
  449.     FailErr( ClearNewHandle( (Handle *)&newObj, sizeof(ObjRecord) ), err, errExit ) ;
  450.     
  451.     /*            Using NewHandleClear saves the following calls:
  452.     WITH newObj** DO
  453.     {
  454.     objContainer = NULL ;
  455.     objContained = NULL ;
  456.     objSelectionData.dataHandle = NULL ;
  457.     objTheWhose = NULL ;
  458.     objValue.dataHandle = NULL ;
  459.     valIsExmn = false ;
  460.     objRedo = false ;
  461.     } ; */
  462.     
  463.     /* <eeh> 4/8 does it really make sense to put a copy of the desc in the record in any case
  464.     but that where it is an object.  Who cares what the input is when it's a text descriptor.
  465.     And will we look pretty silly returning ['text', "spinnaker"] when a memory error occurs? */
  466.     
  467.     (*newObj)->objContained = containedObj ;
  468.     (*newObj)->objValue.descriptorType = typeNull ;
  469.     
  470.     /*set the redo flag so that everything tries to evaluate at least once*/
  471.     (*newObj)->objRedo = true;
  472.     
  473.     HLock( (Handle)newObj ) ;
  474.     
  475.     FailErr( AEDuplicateDesc( input, &(*newObj)->theObjInput ), err, errExit ) ;
  476.     
  477.     switch( input->descriptorType )
  478.     {
  479.     case typeNull:
  480.         (*newObj)->objClass = typeNull ;
  481.         break ;
  482.     
  483.     
  484.     case typeToken :    /* 4/4; dataHandle is to a token descriptor */
  485.     //    WITH newObj** DO
  486.         (*newObj)->objValue = 
  487.                 (*(ContainedTokenRecHandle)(input->dataHandle))->token ;
  488.         (*newObj)->u.tokenClass =
  489.                 (*(ContainedTokenRecHandle)(input->dataHandle))->tokenClass ;
  490.         (*newObj)->objClass = typeToken ;
  491.         (*newObj)->objRedo = false;
  492.         break ;
  493.     
  494.     case typeObjectBeingExamined :
  495.         (*newObj)->objClass = typeObjectBeingExamined ;
  496.         break ;
  497.     
  498.     case typeObjectSpecifier :
  499.         FailErr( AECoerceDesc( input, typeAERecord, &tempRecord ), err, errExit ) ;
  500.     
  501.     //WITH newObj** DO
  502.     /*get the selector form*/
  503.         {
  504.             ObjRecordPtr op = *newObj ;
  505.     
  506.             FailErr( AEGetKeyPtr( &tempRecord, keyAEKeyForm, typeEnumerated,
  507.                     &theReturnedType, (Ptr)&op->u.objForm, sizeof(op->u.objForm),
  508.                     &actualSize), err, errExit ) ;
  509.             
  510.             /*get the desired type*/
  511.             
  512.             FailErr( AEGetKeyPtr( &tempRecord, keyAEDesiredClass, typeType, 
  513.                     &theReturnedType, (Ptr)&op->objClass, SizeOf(op->objClass), &actualSize),
  514.                     err, errExit ) ;
  515.             
  516.             /*get the selector data; put it in the object record so recursive call can get it.*/
  517.             FailErr( AEGetKeyDesc( &tempRecord, keyAEKeyData, typeWildCard,
  518.                     &op->objSelectionData ), err, errExit ) ;
  519.             
  520.             /* 
  521.             HERE IS WHERE WE RECURSIVELY CALL OURSELVES.
  522.             Optimization may occur here. Get the container object.
  523.             */
  524.             
  525.             FailErr( AEGetKeyDesc( &tempRecord, keyAEContainer, typeWildCard,
  526.                     &tempObject ), err, errExit ) ;
  527.             FailErr( CreateObject( &tempObject, newObj, expandWhoseData,
  528.                     &op->objContainer ), err, errExit ) ;
  529.             IgnoreOSErr( AEDisposeDesc( &tempObject ) ) ;
  530.             
  531.             /* Now look at the selector data (which may have been altered by the recursive CreateObject
  532.             call) and if ( it is a whose ) create the test record.  if ( we don't want to dispose of
  533.             the selectionData, set tempObject's Handle to NULL. */
  534.             
  535.             if ( (op->u.objForm == formWhose) && expandWhoseData )
  536.             {
  537.                 FailErr( CreateWhose( op->objSelectionData,
  538.                         (Whose*)&op->objTheWhose ), err, errExit )     ;
  539.                 IgnoreOSErr( AEDisposeDesc( &op->objSelectionData ) ) ;
  540.             }
  541.         
  542.             /* else do nothing: the selectionData already holds tempObject */
  543.             
  544.             /* Now look for simplifications that can/must be done.  If the class of object and its
  545.             container are the same there is the possibility of combining the two operations into
  546.             one.  if ( the form is formTest we MUST optimize; if ( the form of the contained is 
  547.             formAbsolutePosition we can combine the two; if ( it is anything else (for now) we convert the
  548.             test to a phony whose-clause with kAEAll as its index field. */
  549.             
  550.             /* can we combine them?
  551.             NOTE: this is outside the if below because I want to make adding other
  552.             optimizations as easy as possible.   if we decide this is to be all there
  553.             is it should be moved inside. */
  554.             canCombine = (containedObj != NULL)
  555.                     && (op->objClass == (*containedObj)->objClass) ;
  556.             
  557.             /* Now see if there are any optimizations we can make.  Optimizations, in this case,
  558.             mean folding two object records together and combining their selection data into
  559.             a single descriptor.  We attempt to combine the object record associated with
  560.             the current invocation of CreateObj() with that belonging to the invocation that
  561.             called us by folding the necessary stuff into the other and disposing of this one.*/
  562.             
  563.             
  564.             if ( op->u.objForm == formTest )
  565.             {
  566.                 if ( canCombine && ((*containedObj)->u.objForm == formAbsolutePosition)
  567.                     && (((*containedObj)->objSelectionData.descriptorType == typeLongInteger)
  568.                         || (((*containedObj)->objSelectionData.descriptorType
  569.                                 == typeAbsoluteOrdinal)
  570.                                 && IsKnownAbso( **(LongHandle)
  571.                                     (*containedObj)->objSelectionData.dataHandle ) )) )
  572.                 {
  573.                     index.startValue = **((LongHandle)
  574.                             ((*containedObj)->objSelectionData.dataHandle)) ;
  575.                     index.startCase = (*containedObj)->objSelectionData.descriptorType ;        /* was typelongeger */
  576.                     index.stopCase = typeNull ;
  577.                 
  578.                     /* now dispose of the containing obj and fix the pointers */
  579.                     IgnoreOSErr( AEDisposeDesc( &(*containedObj)->objSelectionData ) ) ;
  580.                 }
  581.                 else if ( canCombine && ((*containedObj)->u.objForm == formRange)
  582.                             && RangeIsWhoseable( op->objClass,
  583.                                     (*containedObj)->objSelectionData, &index, &err )
  584.                             && err == noErr )
  585.                 {
  586.                     IgnoreOSErr( AEDisposeDesc( &(*containedObj)->objSelectionData ) ) ;        /* no longer need range */
  587.                 }
  588.                 else if ( err != noErr )            // <eeh> added with port b/c of loss
  589.                 {                                            // of nested procedures
  590.                     goto errExit ;
  591.                 }
  592.                 else
  593.                 {
  594.                     op->u.objForm = formWhose ;
  595.                     index.startCase = typeAbsoluteOrdinal ;
  596.                     index.startValue = (long)kAEAll ;
  597.                     index.stopCase = typeNull ;
  598.                     canCombine = false ;                    /* 4/4 fixes bug where optimization takes place though shouldn't */
  599.                 } 
  600.                 FailErr( AECreateDesc( typeWhoseRangeInternal, (Ptr)&index,
  601.                     sizeof(index), &tempObject ), err, errExit ) ;
  602.                 FailErr( MakeWhoseDescriptor( &tempObject, &op->objSelectionData,
  603.                     &op->objSelectionData ), err, errExit ) ;        /* disposes its inputs */
  604.                 if ( canCombine )            /* really: if ( shouldCombine ... */
  605.                     CombineObjects( &newObj, &containedObj ) ;    /* fold both into 2nd */
  606.             } 
  607.         } // "WITH"
  608.         
  609.         IgnoreOSErr( AEDisposeDesc( &tempRecord ) ) ;
  610.         break ;
  611.     
  612.     default :
  613.     /* This is just a token or descriptor. We will not need to resolve
  614.     it further */
  615.     //WITH newObj** DO
  616.         
  617.         /* The question what value to assign class in the case where an obj's type
  618.          * is 
  619.          * really not distinct from its class is related to that of how to tell whether
  620.          * the value of an obj is a token or a descriptor we own.  Or at least the
  621.          * solutions are likely to be related.
  622.         
  623.          * if ( we get here with a token, ) we must pay careful attention to the class
  624.          * as well as the type of the token.  Yet if ( we get here with, say, as desc
  625.          * of type text and data "string" we were probably called by CreateCompare or 
  626.          * somesuch which has little use for the concept of class.  For now, it's
  627.          * probably best to have those routines pass type as class.  But this whose
  628.          * question is really one that could bear some revisitation.  */
  629.         
  630.             (*newObj)->objClass = input->descriptorType ;
  631.         
  632.         /* <eeh> I assume there is no way this could _ever_ be a token */
  633.         {
  634.             // I WANT TO EXACTLY DUPLICATE THE FUNCTIONALITY OF THE COMMENTED OUT STATEMENT
  635.             //    BELOW.
  636.             AEDesc    tempDesc;
  637.             OSErr        error;
  638.             
  639.             error = AEDuplicateDesc(input, &tempDesc);
  640.             ((*newObj)->objValue).descriptorType = tempDesc.descriptorType;
  641.             ((*newObj)->objValue).dataHandle = tempDesc.dataHandle;
  642.             if (error)
  643.                 FailErr(error, err, errExit);
  644.         }
  645.     //        FailErr( AEDuplicateDesc( input, &(*newObj)->objValue ), err, errExit ) ;
  646.             /* caller knows whether to dispose input */
  647.             
  648.             (*newObj)->objRedo = false;
  649.     
  650.         } // switch
  651.     
  652.         /*        IgnoreOSErr( AEDisposeDesc( tempObject )) ;            */
  653.         /*        pAssert( tempObject.dataHandle = NULL, 'was not NULL' ) ;    */
  654.     
  655.         HUnlock( (Handle)newObj ) ;
  656.         *theObject = newObj;
  657.         return err ;
  658.     
  659.     
  660.     FAIL_ERR_PROC(err, errExit)
  661.         if ( newObj != NULL )
  662.         {
  663.             HLock( (Handle)newObj ) ;
  664.     //        WITH newObj** DO
  665.             {
  666.                 ObjRecordPtr op = *newObj ;
  667.                 if ( ! SetErrDesc( op->theObjInput ) )
  668.                     IgnoreOSErr( AEDisposeDesc( &(*newObj)->theObjInput ) ) ;
  669.                 IgnoreOSErr( AEDisposeDesc( &op->objSelectionData ) ) ;    
  670.                 DisposeWhose( (Whose)op->objTheWhose ) ;                    /* <eeh> Do I need this? */
  671.                 DisposeObj( op->objContainer ) ;
  672.             }
  673.             DisposeHandle( (Handle) newObj ) ;
  674.         } 
  675.         IgnoreOSErr( AEDisposeDesc( &tempObject ) ) ;
  676.         IgnoreOSErr( AEDisposeDesc( &tempRecord ) ) ;
  677.         *theObject = NULL;
  678.     END_FAIL_ERR_PROC(err)
  679.     
  680. } /*CreateObject*/
  681.  
  682.  
  683.  
  684. void
  685. zero( char *s, long bytes )
  686. {
  687.     while ( bytes-- )
  688.         *s++ = 0 ;
  689. }
  690.  
  691. static OSErr
  692. CreateCompareEvt( AEDesc *input, CompareEvent *output)
  693. {
  694.     CompareEvtRecord cer ;
  695.     OSErr err = noErr ;
  696.     CompareEvent newCompEvnt = NULL ;
  697.     DescType theRtndType ; 
  698.     DescType cEventClass ; 
  699.     DescType cEventID ; 
  700.     long actualSize ;
  701.     ProcessSerialNumber psn = { 0, kCurrentProcess } ;
  702.     AEAddressDesc target ;
  703.     AEDesc params, tempDesc ;
  704.     AEKeyword theAEKeyword ;
  705.     long numElements ;
  706.  
  707.     zero( (char *)&cer, sizeof(cer) ) ;
  708.     params.dataHandle = NULL ;
  709.     target.dataHandle = NULL ;
  710.     tempDesc.dataHandle = NULL ;
  711.  
  712.     FailErr( AECreateDesc( typeProcessSerialNumber, (Ptr)&psn, sizeof(psn),
  713.             &target ), err, errExit ) ;
  714.  
  715.     FailErr( AEGetKeyPtr( input, keyEventClassParam, typeType, 
  716.             &theRtndType, (Ptr)&cEventClass, sizeof(cEventClass), &actualSize ),
  717.             err, errExit ) ;
  718.  
  719.     FailErr( AEGetKeyPtr( input, keyEventIDParam, typeType, 
  720.             &theRtndType, (Ptr)&cEventID, sizeof(cEventID), &actualSize),
  721.             err, errExit ) ;
  722.  
  723.     FailErr( AECreateAppleEvent( cEventClass, cEventID, &target,
  724.             kAutoGenerateReturnID, kAnyTransactionID, &cer.eventWParams ),
  725.             err, errExit ) ;
  726.     
  727.     IgnoreOSErr( AEDisposeDesc( &target ) ) ;
  728.  
  729.     // now move the params from the incomming descriptor to the AppleEvent
  730.     // we'll be sending as the event.
  731.  
  732.     FailErr( AEGetKeyDesc( input, keyCompEvtParams, typeAERecord,
  733.             ¶ms ), err, errExit ) ;
  734.  
  735.     FailErr( AECountItems( ¶ms, &numElements ), err, errExit ) ;
  736.     while ( numElements )
  737.     {
  738.         FailErr( AEGetNthDesc( ¶ms, numElements, typeWildCard,
  739.                 &theAEKeyword, &tempDesc ), err, errExit ) ;
  740.         FailErr( AEPutParamDesc( &cer.eventWParams, theAEKeyword, &tempDesc ),
  741.                 err, errExit ) ;
  742.         IgnoreOSErr( AEDisposeDesc( &tempDesc ) ) ;
  743.         --numElements ;
  744.     }
  745.     IgnoreOSErr( AEDisposeDesc( ¶ms ) ) ;
  746.  
  747.  
  748.     cer.value = false ;
  749.     cer.redo = true ;
  750.     
  751. //    FailErr( AEDuplicateDesc( input, &cer.theCompEvtInput ), err, errExit ) ;
  752.     cer.theCompEvtInput = *input ;
  753.     input->dataHandle = NULL ;                // so the later dispose won't do any harm
  754.  
  755.     DebugStr("\pWarning: PtrToHand being called. Result will be wrong.");
  756.     PtrToHand( &cer, (Handle *)&newCompEvnt, sizeof(cer) ) ;
  757.     FailErr( MemError(), err, errExit ) ;
  758.     
  759.     *output = newCompEvnt ;
  760.         
  761. FAIL_ERR_PROC(err, errExit)
  762.     if ( cer.eventWParams.dataHandle )
  763.         IgnoreOSErr( AEDisposeDesc( &cer.theCompEvtInput ) ) ;
  764.     if ( target.dataHandle )
  765.         IgnoreOSErr( AEDisposeDesc( &target ) ) ;
  766.     if ( tempDesc.dataHandle )
  767.         IgnoreOSErr( AEDisposeDesc( &tempDesc ) ) ;
  768. END_FAIL_ERR_PROC(err)
  769.  
  770. } // CreateCompareEvt
  771.  
  772.  
  773.  
  774.     /*———————————————————————— CreateTerm ————————————————————————*/
  775.  
  776. /*create a term record from either a typeLogicalDescriptor or 
  777.  * a typeCompDescriptor*/
  778. OSErr
  779. CreateTerm( AEDesc  *input, Term *theTerm )
  780. {
  781.     OSErr err = noErr;
  782.     
  783.     FailErr( ClearNewHandle( (Handle *)theTerm, sizeof(TestTermRecord) ),
  784.             err, errExit ) ;
  785.  
  786. /*            Using NewHandleClear saves the following calls:
  787.     WITH theTerm^^ DO
  788.         {
  789.             next := NULL ;
  790.             value := false ;
  791.             redo := false ;
  792.             ttype := kCompare ;
  793.             comp/log := NULL ;
  794.         } ; */
  795.  
  796.     HLock( (Handle) *theTerm ) ;
  797.     FailErr( AEDuplicateDesc( input, &(**theTerm)->theTermInput ), err, errExit ) ;
  798.     
  799. //    WITH theTerm^^ DO
  800.     {
  801.         register TestTermPtr tp = **theTerm ;
  802.         switch ( input->descriptorType )
  803.         {    
  804.             case typeLogicalDescriptor :
  805.                 tp->ttype = kLogical;
  806.                 FailErr( CreateLogical( input, &tp->u.log ), err, errExit ) ;
  807.                 break ;
  808.             case typeCompDescriptor :
  809.                 tp->ttype = kCompare ;
  810.                 FailErr( CreateCompare( *input, &tp->u.compar ), err, errExit ) ;
  811.                 break ;
  812.             case typeCompEvtDescriptor :
  813.                 tp->ttype = kCompareEvt ;
  814.                 FailErr( CreateCompareEvt( input, &tp->u.cEvt ),
  815.                         err, errExit ) ;
  816.                 break ;
  817.             default :
  818.                 err = errAEBadTestKey ;
  819.                 goto errExit ;
  820.         }
  821.                                 
  822.         
  823.         /* set the redo flag so that everything tries to evaluate at least once */
  824.         tp->redo = true;
  825.     }
  826.     
  827.     HUnlock( (Handle) *theTerm ) ;
  828.     IgnoreOSErr( AEDisposeDesc( input ) ) ;
  829.  
  830. FAIL_ERR_PROC(err, errExit)
  831.     if ( *theTerm != NULL )
  832.     {
  833.         if ( SetErrDesc( (**theTerm)->theTermInput ) )    
  834.             (**theTerm)->theTermInput.dataHandle = NULL ;
  835.         if ( (**theTerm)->ttype == kLogical )
  836.             DisposeLogical( (Logical)(**theTerm)->u.log ) ;
  837.         else
  838.             DisposeCompare((Comparison)(**theTerm)->u.compar ) ;
  839.         DisposeTerm( (**theTerm)->next ) ;
  840.     }
  841.     DisposeHandle( (Handle)*theTerm ) ;
  842.     *theTerm = NULL ;
  843. END_FAIL_ERR_PROC(err)
  844.  
  845. }  /* CreateTerm */
  846.  
  847.  
  848.     /*———————————————————————— CreateWhose ————————————————————————*/
  849.  
  850. static OSErr
  851. AdjustIndexValue( long  *result, DescType *specialCase )
  852. {
  853.     if ( *specialCase == typeAbsoluteOrdinal )
  854.     {
  855.         *specialCase = (DescType)*result ;
  856.         *result = 1 ;
  857.  
  858.         if ( *specialCase == kAEFirst )
  859.                 *specialCase = typeLongInteger ;
  860.         else if ( *specialCase == kAELast )
  861.         {
  862.             *specialCase = typeLongInteger ;
  863.             *result = -1 ;
  864.         }
  865.         
  866.         /* Certain special relative forms are not allowed in whose ranges */
  867.         /* <eeh> removed test for kAENext etc.  No longer considered in same class
  868.           as Last, Any etc. */
  869.     }
  870.     else if ( (*specialCase != typeLongInteger) && (*specialCase != typeNull) )
  871.         return errAEImpossibleRange ;
  872.  
  873.     return noErr ;
  874. } // AdjustIndexValue
  875.  
  876.  
  877.  
  878.  
  879. OSErr
  880. CreateWhose( AEDesc  input ,        /* do not dispose: may be a whose descriptor an accessor expects to use later */
  881.             Whose *theWhose )
  882.         /*create a Whose record by unpacking the whose descriptor in a range*/
  883. {        
  884.     AEDesc         tempObject ;
  885.     AEDesc         tempRecord ;
  886. //    DescType         theReturnedType ;            not used in Pascal original
  887. //    Size         actualSize ;                            same here
  888.     OSErr err = noErr ;
  889.             
  890.         tempObject.dataHandle = NULL;
  891.         tempRecord.dataHandle = NULL;
  892.         
  893.         FailErr( ClearNewHandle( (Handle *)theWhose, sizeof(WhoseRecord) ),
  894.                 err, errExit ) ;
  895.  
  896. /*            Using NewHandleClear saves the following calls:
  897.         WITH theWhose^^ DO
  898.             {
  899.                 index.start := 0 ;
  900.                 index.stop := 0 ;
  901.                 theTerm := NULL ;
  902.                 value.dataHandle := NULL ;
  903.             } ;
  904. */
  905.  
  906.         HLock( (Handle) *theWhose ) ;
  907.         FailErr( AEDuplicateDesc( &input, &(**theWhose)->theWhoseInput ),
  908.                 err, errExit ) ;
  909.         
  910.         FailErr( AECoerceDesc( &input, typeAERecord, &tempRecord ),
  911.                 err, errExit ) ;
  912.  
  913. //            WITH theWhose^^ DO
  914.         {
  915.             WhoseRecordPtr wpr = **theWhose ;                
  916.  
  917.             /*get the selector data, and if ( it is a whose ) create the Whose record*/
  918.             FailErr( AEGetKeyDesc( &tempRecord, keyAETest, typeWildCard,
  919.                 &tempObject ), err, errExit ) ;
  920.             FailErr( CreateTerm( &tempObject, &wpr->theTerm ),
  921.                     err, errExit) ;
  922.  
  923.             FailErr( AEGetKeyDesc( &tempRecord, keyAEIndex, typeWildCard,
  924.                     &tempObject ), err, errExit ) ;
  925.  
  926.             if ( tempObject.descriptorType == typeWhoseRangeInternal )
  927.             {
  928.                 BlockMove( *(tempObject.dataHandle), (Ptr)&wpr->index,
  929.                         sizeof(wpr->index) ) ;
  930.                 FailErr( AdjustIndexValue( &wpr->index.startValue,
  931.                     &wpr->index.startCase ), err, errExit ) ;
  932.                 FailErr( AdjustIndexValue( &wpr->index.stopValue,
  933.                     &wpr->index.stopCase ), err, errExit )
  934.             }
  935.             else
  936.             {
  937.                 wpr->index.startValue = **((LongHandle)tempObject.dataHandle) ;
  938.                 wpr->index.startCase = tempObject.descriptorType ;
  939.                 FailErr( AdjustIndexValue( &wpr->index.startValue, 
  940.                         &wpr->index.startCase ), err, errExit ) ;
  941.                 wpr->index.stopCase = typeNull ;
  942.             }
  943.         
  944.             IgnoreOSErr( AEDisposeDesc( &tempObject ) ) ;
  945.             IgnoreOSErr( AEDisposeDesc( &tempRecord ) ) ;
  946.         }
  947.         
  948.         HUnlock( (Handle) *theWhose ) ;
  949.  
  950. FAIL_ERR_PROC(err, errExit)
  951.     if ( *theWhose != NULL )
  952.     {
  953.         if ( SetErrDesc( (**theWhose)->theWhoseInput ) )
  954.             (**theWhose)->theWhoseInput.dataHandle = NULL ;
  955.         DisposeTerm( (**theWhose)->theTerm ) ;
  956.     }
  957.     IgnoreOSErr( AEDisposeDesc( &tempObject ) ) ;
  958.     IgnoreOSErr( AEDisposeDesc( &tempRecord ) ) ;
  959.     DisposeHandle( (Handle)*theWhose ) ;
  960.     *theWhose = NULL;
  961. END_FAIL_ERR_PROC(err)
  962.  
  963. } /*CreateWhose*/
  964.         
  965.